﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using static System.Net.WebRequestMethods;

namespace StateManager
{
    public static class TypeFileCache
    {
        static List<TypeFile> typeFilesCache = new List<TypeFile>();
        /// <summary>
        /// 加载类库文件到内存
        /// </summary>
        /// <param name="typeName">类型名</param>
        /// <param name="file">类库文件名，相对程序所在目录，也可以是资源文件（宿主类库文件:资源文件）</param>
        /// <param name="onFileLoded"></param>
        /// <returns></returns>
        public static TypeFile AddCache(string typeName, string file, Action<string> onFileLoded)
        {
            //type能匹配到，则返回
            TypeFile match = typeFilesCache.Find(t => t.TypeName == typeName);
            if (match != null)
                return match;

            Assembly asm = typeFilesCache.Find(t => t.File == file)?.Asm;
            //file已加载？
            if (asm == null)
            {
                //尝试从文件夹加载
                if (!file.Contains(":"))
                {
                    string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file);
                    //确认是程序集文件，才能加载
                    AssemblyName testAssembly = AssemblyName.GetAssemblyName(filePath);
                    asm = Assembly.LoadFile(filePath);

                    onFileLoded?.Invoke(filePath);

                }
                //尝试从资源文件加载
                else
                {
                    string[] fileEmbed = file.Split(':');//宿主类库文件:资源文件
                    //加载宿主文件
                    TypeFile hostFile = TypeFileCache.AddCache(typeName + "_host", fileEmbed[0], onFileLoded);
                    //加载资源文件
                    using (var _stream = hostFile.Asm.GetManifestResourceStream(fileEmbed[1]))
                    {
                        if (_stream != null)
                        {
                            byte[] _data = new byte[_stream.Length];
                            _stream.Read(_data, 0, _data.Length);
                            asm = Assembly.Load(_data);

                            onFileLoded?.Invoke(fileEmbed[1]);

                        }
                    }
                }
            }

            TypeFile item = new TypeFile();
            item.TypeName = typeName;
            item.File = file;
            item.Asm = asm;
            item.Type = item.Asm.GetExportedTypes()?.Where(o => o.IsClass)
                .Where(o => o.FullName == item.TypeName)
                //.Where(o => o.GetInterface(typeof(IState).FullName) != null)
                .FirstOrDefault();
            typeFilesCache.Add(item);
            return item;
        }
        public static Type GetTypeByName(string typeName)
        {
            return typeFilesCache.Find(t => t.TypeName == typeName)?.Type;
        }
    }
}
